
module frv_ifu_top (
    input                   clk             ,
    input                   rst_n           ,
    // Program Downloader reset
    input                   pd_rst          ,
    // Instruction Mem Interface
    output                  imem_req        ,
    output [31:0]           imem_addr       ,
    input [31:0]            imem_data       ,
    input                   imem_vld        , // ignore it when the cache module is not ready
    output                  imem_flush      ,
    // BP Interface    
    input                   bru_flush       , // vld when branch prediction fail
    input                   bru_update_vld  , // vld when branch behavior happen 
    input [31:0]            bru_btb_taddr   , // BTB target addr value
    input [31:0]            bru_pc_data     , 
    input                   bru_taken       ,       
    input [3:0]             bru_bht_val     , // BHT Entry Value
    input [31:0]            bru_pht_val     , // PHT Entry Value
    // Exception Interface
    input                   exp_flush       , 
    input  [4:0]            exp_code        , 
    input  [31:0]           exp_taddr       ,
    // Inst Buffer Interface                    
    input                   ib_rreq         ,  
    output                  ib_inst_vld     ,  
    output [31:0]           ib_inst_data    ,  
    output [31:0]           ib_pc_data      ,  
    output                  ib_exp_vld      , 
    output [4:0]            ib_exp_code     , 
    output [31:0]           ib_bp_taddr     , // bp target addr
    output                  ib_bp_taken     , 
    output [3:0]            ib_bp_bhtv      , // BHT Entry Value
    output [31:0]           ib_bp_phtv        // PHT Entry Value
);

wire [31:0]           bp_taddr        ; 
wire                  bp_branch_taken ; 
wire [3:0]            bp_bhtv         ; 
wire [31:0]           bp_phtv         ; 

wire                  ifu_ib_wreq     ; 
wire [31:0]           ifu_ib_pc_data  ; 
wire                  ifu_ib_exp_vld  ; 
wire [4:0]            ifu_ib_exp_code ; 
wire [31:0]           ifu_ib_bp_taddr ; 
wire                  ifu_ib_bp_taken ; 
wire [3:0]            ifu_ib_bp_bhtv  ; 
wire [31:0]           ifu_ib_bp_phtv  ; 

wire                  ib_flush        ; 
wire                  ib_wreq         ; 
wire [31:0]           ib_inst_data_i  ; 
wire [31:0]           ib_pc_data_i    ; 
wire                  ib_exp_vld_i    ; 
wire [4:0]            ib_exp_code_i   ; 
wire [31:0]           ib_bp_taddr_i   ; 
wire                  ib_bp_taken_i   ; 
wire [3:0]            ib_bp_bhtv_i    ; 
wire [31:0]           ib_bp_phtv_i    ; 

wire                  ib_vld_o        ; 
wire [31:0]           ib_inst_data_o  ; 
wire [31:0]           ib_pc_data_o    ; 
wire                  ib_exp_vld_o    ; 
wire [4:0]            ib_exp_code_o   ; 
wire [31:0]           ib_bp_taddr_o   ; 
wire                  ib_bp_taken_o   ; 
wire [3:0]            ib_bp_bhtv_o    ; 
wire [31:0]           ib_bp_phtv_o    ; 
wire                  ib_rdy        ; 

assign ib_flush       = bru_flush || exp_flush;
assign ib_wreq        = ifu_ib_wreq && ~bru_flush && ~exp_flush ;  
assign ib_inst_data_i = imem_data             ;  
assign ib_pc_data_i   = ifu_ib_pc_data        ;  
assign ib_exp_vld_i   = ifu_ib_exp_vld        ;  
assign ib_exp_code_i  = ifu_ib_exp_code       ;  
assign ib_bp_taddr_i  = ifu_ib_bp_taddr       ;  
assign ib_bp_taken_i  = ifu_ib_bp_taken       ;  
assign ib_bp_bhtv_i   = ifu_ib_bp_bhtv        ;  
assign ib_bp_phtv_i   = ifu_ib_bp_phtv        ;  

// Port Connection

assign ib_inst_vld     = ib_vld_o        ;
assign ib_inst_data    = ib_inst_data_o  ;
assign ib_pc_data      = ib_pc_data_o    ;
assign ib_exp_vld      = ib_exp_vld_o    ;
assign ib_exp_code     = ib_exp_code_o   ;
assign ib_bp_taddr     = ib_bp_taddr_o   ;
assign ib_bp_taken     = ib_bp_taken_o   ;
assign ib_bp_bhtv      = ib_bp_bhtv_o    ;
assign ib_bp_phtv      = ib_bp_phtv_o    ;

// Branch Prediction Port
assign bp_taddr        = 0;
assign bp_branch_taken = 0;
assign bp_bhtv         = 0;
assign bp_phtv         = 0;

frv_ifu_reqgen _frv_ifu_reqgen(
.clk                (clk            ),
.rst_n              (rst_n          ),
.pd_rst             (pd_rst         ),
.bp_taddr           (bp_taddr       ),
.bp_branch_taken    (bp_branch_taken),
.bp_bhtv            (bp_bhtv        ),
.bp_phtv            (bp_phtv        ),
.exp_flush          (exp_flush      ),               
.exp_taddr          (exp_taddr      ),
.bru_flush          (bru_flush      ),
.bru_btb_taddr      (bru_btb_taddr  ),           
.ib_ready           (ib_rdy       ),
.imem_req           (imem_req       ),
.imem_addr          (imem_addr      ),
.ifu_ib_wreq        (ifu_ib_wreq    ),
.ifu_ib_pc_data     (ifu_ib_pc_data ),
.ifu_ib_exp_vld     (ifu_ib_exp_vld ),
.ifu_ib_exp_code    (ifu_ib_exp_code),
.ifu_ib_bp_taddr    (ifu_ib_bp_taddr),
.ifu_ib_bp_taken    (ifu_ib_bp_taken),
.ifu_ib_bp_bhtv     (ifu_ib_bp_bhtv ), // BHT Entry Value
.ifu_ib_bp_phtv     (ifu_ib_bp_phtv )  // PHT Entry Value       
);


frv_ifu_ibuf _frv_ifu_ibuf(
.clk                (clk           ),
.rst_n              (rst_n         ),
.pd_rst             (pd_rst        ),
.ib_flush           (ib_flush      ),
.ib_wreq            (ib_wreq       ),
.ib_inst_data_i     (ib_inst_data_i),
.ib_pc_data_i       (ib_pc_data_i  ),
.ib_exp_vld_i       (ib_exp_vld_i  ),
.ib_exp_code_i      (ib_exp_code_i ),
.ib_bp_taddr_i      (ib_bp_taddr_i ),
.ib_bp_taken_i      (ib_bp_taken_i ),
.ib_bp_bhtv_i       (ib_bp_bhtv_i  ), // BHT Entry Value
.ib_bp_phtv_i       (ib_bp_phtv_i  ), // PHT Entry Value
.ib_rreq            (ib_rreq       ), // ibuf read request
.ib_vld_o           (ib_vld_o      ),
.ib_inst_data_o     (ib_inst_data_o),
.ib_pc_data_o       (ib_pc_data_o  ),
.ib_exp_vld_o       (ib_exp_vld_o  ),
.ib_exp_code_o      (ib_exp_code_o ),
.ib_bp_taddr_o      (ib_bp_taddr_o ),
.ib_bp_taken_o      (ib_bp_taken_o ),
.ib_bp_bhtv_o       (ib_bp_bhtv_o  ), // BHT Entry Value
.ib_bp_phtv_o       (ib_bp_phtv_o  ), // PHT Entry Value
.ib_ready           (ib_rdy      ) 
); 

endmodule


